#!/bin/sh
#
# Copyright 2015-2020 The OpenZipkin Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.
#

# This script is only a convenience as the build environment is controlled in
# the Dockerfile. That said, it uses only basic shell commands to help it work
# on developer laptops as well as CI nodes. Mainly, this centralizes the base
# Java image mappings and ensures all metadata needed is taken from pom.xml.
set -ue

if ! test -f docker/Dockerfile; then
  echo Please execute this script from the repository root
  exit 1
fi

PROJECT="Zipkin"
TAG=${1:-openzipkin/zipkin:test}
# Default the version to the pom when unset
POM_VERSION=${POM_VERSION:-$(mvn help:evaluate -N -Dexpression=project.version -q -DforceStdout)}
RELEASE_VERSION=${2:-${POM_VERSION}}
OP=${3:-load}

DOCKER_TARGET=$(echo $TAG|sed -e 's~.*/\(.*\):.*~\1~g')
# When true and building zipkin zipkin-slim or zipkin-ui, use zipkin-exec.jar and zipkin-slim.jar
# produced by a Maven build. This is implicitly true when a SNAPSHOT version.
RELEASE_FROM_MAVEN_BUILD=${RELEASE_FROM_MAVEN_BUILD:-false}

# When publishing jars, we build with JDK 11 to ensure we can write 1.6 zipkin.jar for Brave.
# However, when creating Docker images, there's no such requirement.
# Hence, we use one version to keep the layer count manageable and centralized here.
JAVA_VERSION=${JAVA_VERSION:-15.0.1_p9}

# Platforms to eventually push to the registry
PLATFORMS="linux/amd64,linux/arm64"

# Use a quay.io mirror to prevent build outages due to Docker Hub pull quotas
# Use latest from https://quay.io/repository/app-sre/nginx?tab=tags
NGINX_VERSION=1.19.2
DOCKER_ARGS=""
case ${DOCKER_TARGET} in
  zipkin )
    DOCKERFILE_PATH=docker/Dockerfile
    ;;
  zipkin-slim )
    DOCKERFILE_PATH=docker/Dockerfile
    ;;
  zipkin-ui )
    DOCKERFILE_PATH=docker/Dockerfile
    DOCKER_ARGS=" --label nginx-version=${NGINX_VERSION}"
    ;;
  zipkin-kafka )
    DOCKERFILE_PATH=docker/collector/kafka/Dockerfile
    # Use latest release from: https://kafka.apache.org/downloads
    KAFKA_VERSION=2.6.0
    DOCKER_ARGS=" --build-arg kafka_version=${KAFKA_VERSION} --label kafka-version=${KAFKA_VERSION}"
    # Note: Scala 2.13+ supports JRE 14
    DOCKER_ARGS="${DOCKER_ARGS} --build-arg scala_version=2.13"
    ;;
  zipkin-cassandra )
    DOCKERFILE_PATH=docker/storage/cassandra/Dockerfile
    # Until Cassandra v4, we are stuck on JRE 8 for Cassandra
    JAVA_VERSION=8.252.09
    # Use latest stable version: https://cassandra.apache.org/download/
    CASSANDRA_VERSION=3.11.9
    DOCKER_ARGS=" --build-arg cassandra_version=${CASSANDRA_VERSION} --label cassandra-version=${CASSANDRA_VERSION}"
    # Currently crashes on arm64 per: https://issues.apache.org/jira/browse/CASSANDRA-16212
    # When this works, we'll also need to fix the install script to use a different port because
    # buildx will run the two arch builds simultaneously.
    PLATFORMS="linux/amd64"
    ;;
  zipkin-elasticsearch6 )
    DOCKERFILE_PATH=docker/storage/elasticsearch6/Dockerfile
    # Use latest 6.x version from https://www.elastic.co/downloads/past-releases#elasticsearch
    ELASTICSEARCH_VERSION=6.8.13
    DOCKER_ARGS=" --build-arg elasticsearch_version=${ELASTICSEARCH_VERSION} --label elasticsearch-version=${ELASTICSEARCH_VERSION}"
    ;;
  zipkin-elasticsearch7 )
    DOCKERFILE_PATH=docker/storage/elasticsearch7/Dockerfile
    # Use latest 7.x version from https://www.elastic.co/downloads/past-releases#elasticsearch
    ELASTICSEARCH_VERSION=7.9.3
    DOCKER_ARGS=" --build-arg elasticsearch_version=${ELASTICSEARCH_VERSION} --label elasticsearch-version=${ELASTICSEARCH_VERSION}"
    ;;
  zipkin-mysql )
    DOCKERFILE_PATH=docker/storage/mysql/Dockerfile
    # Use latest from https://pkgs.alpinelinux.org/packages?name=mysql
    MYSQL_VERSION=10.5.6
    DOCKER_ARGS=" --build-arg mysql_version=${MYSQL_VERSION} --label mysql-version=${MYSQL_VERSION}"
    ;;
  * )
    echo "Invalid TAG: ${TAG}, Ex. openzipkin/zipkin:test"
    exit 1
esac

# We don't currently release from a remote snapshot repository. When the version is snapshot, this
# is a local build or a pull request. Look to see if the files the build would produce are present.
# This allows skipping the build when an upstream step or stage has already produced them.
if [ ${DOCKERFILE_PATH} = docker/Dockerfile ]; then
  # Set NGINX build arg always as the default Docker file uses it
  DOCKER_ARGS="${DOCKER_ARGS} --build-arg nginx_version=${NGINX_VERSION}"

  case "${RELEASE_VERSION}" in
    *-SNAPSHOT )
      if [ -f "zipkin-server/target/zipkin-server-${RELEASE_VERSION}-exec.jar" ] &&
         [ -f "zipkin-server/target/zipkin-server-${RELEASE_VERSION}-slim.jar" ]; then
        echo Re-using ${PROJECT} ${RELEASE_VERSION} binaries from a previous build...
      elif [ ${RELEASE_FROM_MAVEN_BUILD} = true ]; then
        echo "RELEASE_FROM_MAVEN_BUILD=true, but required binaries are not present"
        exit 1
      else
        if [ ${RELEASE_VERSION} != ${POM_VERSION} ]; then
          echo "To build ${PROJECT} implicitly, run: docker/build_image ${TAG} ${POM_VERSION}"
          exit 1
        fi

        echo Building ${PROJECT} ${RELEASE_VERSION}...
        # Skips tests and license to run faster and allow shallow clones
        ./mvnw -T1C -q --batch-mode -DskipTests -Dlicense.skip=true --also-make -pl zipkin-server clean package
      fi
      RELEASE_FROM_MAVEN_BUILD=true
      ;;
  esac
fi

DOCKER_ARGS="-f ${DOCKERFILE_PATH} --target ${DOCKER_TARGET} --tag ${TAG} ${DOCKER_ARGS} \
--build-arg release_version=${RELEASE_VERSION} --label zipkin-version=${RELEASE_VERSION} \
--build-arg release_from_maven_build=${RELEASE_FROM_MAVEN_BUILD} \
--build-arg java_version=${JAVA_VERSION} \
--label org.opencontainers.image.source=https://github.com/openzipkin/zipkin \
--label org.opencontainers.image.version=${RELEASE_VERSION} ."

# Avoid buildx for two reasons:
#  * It only supports one platform/arch on load https://github.com/docker/buildx/issues/59
#  * It would pull Docker Hub for moby/buildkit or multiarch/qemu-user-static images, using up quota
if [ "${OP}" = "load" ]; then
  echo "Building image ${TAG} with java_version ${JAVA_VERSION}"
  docker build ${DOCKER_ARGS}
  exit $?
fi

if [ "${OP}" != "push" ]; then
  echo "Invalid OP: ${OP}, Ex. load or push"
  exit 1
fi

# This can be less manual in the future, for example checking buildx to see what it can do.
ARCH=${ARCH:-$(uname -m)}
case ${ARCH} in
  x86_64* )
    ;;
  amd64* )
    ;;
  * )
    echo Pushing platforms ${PLATFORMS} with arch ${ARCH} is not yet supported.
    exit 1
esac

echo "Pushing image ${TAG} with platforms ${PLATFORMS} and Java version ${JAVA_VERSION}"
docker buildx build --progress plain --platform=${PLATFORMS} ${DOCKER_ARGS} --push
